package com.example.spidertp.core;

import com.example.spidertp.exception.BusinessException;
import com.example.spidertp.handler.SpiderRejectedPolicy;
import com.example.spidertp.handler.SpiderThreadFactory;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * 提供单例的SpiderThreadPool线程池对象
 *
 * @author xiong.bo
 * @version 1.0
 * @date 2022/9/13 10:02 下午
 */
public class SpiderThreadPoolFactory {


    /**
     * 定义管理线程池的Map,例如可以根据业务类型来创建对应的线程池
     * 前提是线程的总和也要在机器的最大支持之内
     */
    private static volatile Map<String, SpiderThreadPool> poolMap = new HashMap<>(8);

    /**
     * 通过线程池的class地址拿到线程池名称
     */
    private static volatile Map<String, String> poolClassMap = new HashMap<>(8);

    private SpiderThreadPoolFactory() {
    }

    /**
     * 外界对poolMap只有访问权限，没有修改权限
     *
     * @return
     */
    public static Map<String, SpiderThreadPool> getPoolMap() {
        return poolMap;
    }

    public static Map<String, String> getPoolClassMap() {
        return poolClassMap;
    }

    /**
     * 获取指定分类的线程池
     *
     * @param poolName
     * @return
     */
    public static SpiderThreadPool getThreadPool(String poolName) {
        if (ObjectUtils.isEmpty(poolName)) {
            throw new BusinessException("线程池名称不能为空");
        }
        return poolMap.get(poolName);
    }

    /**
     * 初始化一个新的线程池
     * 核心参数都给默认值
     *
     * @param poolName 线程池名称
     * @return
     */
    public static SpiderThreadPool createThreadPool(String poolName,
                                                    int corePoolSize,
                                                    int maxPoolSize,
                                                    long keepAliveTime,
                                                    int capacity) {
        if (ObjectUtils.isEmpty(poolName)) {
            throw new BusinessException("线程池名称不能为空");
        }
        SpiderThreadPool threadPool;
        synchronized (SpiderThreadPoolFactory.class) {
            threadPool = poolMap.get(poolName);
            if (null != threadPool) {
                throw new BusinessException("线程池[" + poolName + "]已存在");
            }
            threadPool = new SpiderThreadPool(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(capacity), new SpiderThreadFactory(poolName), new SpiderRejectedPolicy());
            threadPool.setQueueCapacity(capacity);
            poolMap.put(poolName, threadPool);
            poolClassMap.put(String.valueOf(System.identityHashCode(threadPool)), poolName);
        }
        return threadPool;
    }

}
